/*
Copyright 2024 - 2025 Zen HuiFer

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net"

	"github.com/dustin/go-coap"
	"go.uber.org/zap"
)

func getUid(remoteAdd string) string {
	zap.S().Infof("getUid 开始, remoteAdd = %v", remoteAdd)
	val := globalRedisClient.HGet(context.Background(), "coap_uid_f:"+globalConfig.NodeInfo.Name, remoteAdd).Val()
	return val
}

func storageUid(uid, remoteAdd string) {
	zap.S().Infof("storageUid 开始, uid = %v, remoteAdd = %v", uid, remoteAdd)
	globalRedisClient.HSet(context.Background(), "coap_uid:"+globalConfig.NodeInfo.Name, uid, remoteAdd)
	globalRedisClient.HSet(context.Background(), "coap_uid_f:"+globalConfig.NodeInfo.Name, remoteAdd, uid)
}
func RemoveUid(remoteAdd string) {
	zap.S().Infof("RemoveUid 开始, remoteAdd = %v", remoteAdd)
	val := globalRedisClient.HGet(context.Background(), "coap_uid_f:"+globalConfig.NodeInfo.Name, remoteAdd).Val()
	if val == "" {
		return
	} else {
		globalRedisClient.HDel(context.Background(), "coap_uid:"+globalConfig.NodeInfo.Name, val)
		globalRedisClient.HDel(context.Background(), "coap_uid_f:"+globalConfig.NodeInfo.Name, remoteAdd)

	}
}

func Create(port int) {
	zap.S().Infof("Create 开始, port = %v", port)
	mux := coap.NewServeMux()
	mux.Handle("/auth", coap.FuncHandler(auth))                          //创建 "/auth"处理接口
	mux.Handle("/data", coap.FuncHandler(data))                          //创建 "/data"处理接口
	log.Fatal(coap.ListenAndServe("udp", fmt.Sprintf(":%d", port), mux)) //启动Server 端口为5683 这里为什么要用":5683"?搞不明白

}

type Auth struct {
	Username string `json:"username"`
	Password string `json:"password"`
	DeviceId string `json:"device_id"`
}

func auth(l *net.UDPConn, a *net.UDPAddr, m *coap.Message) *coap.Message {

	if m.IsConfirmable() {

		auth := &Auth{}
		err := json.Unmarshal(m.Payload, auth)
		if err != nil {
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("安全认证信息异常"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			return res
		}

		up, s := FindDeviceMappingUP(auth.DeviceId)

		if up != auth.Username || s != auth.Password {
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("安全认证信息异常"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			return res
		}

		mc := globalRedisClient.HRandField(context.Background(), "coap_uid_f:"+globalConfig.NodeInfo.Name, -1).Val()

		if int64(len(mc)) <= globalConfig.NodeInfo.Size {
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("安全认证成功"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			storageUid(auth.DeviceId, a.String())
			CoapMap[a.String()] = l
			return res
		} else {
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("当前设备数量已达上线"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			return res
		}
	}
	return nil
}

var CoapMap = make(map[string]*net.UDPConn)

func data(l *net.UDPConn, a *net.UDPAddr, m *coap.Message) *coap.Message {
	if m.IsConfirmable() {
		uid := getUid(a.String())

		if uid != "" {
			coapMsg := CoapMessage{
				Uid:     uid,
				Message: string(m.Payload),
			}
			jsonData, err := json.Marshal(coapMsg)
			if err != nil {
				zap.S().Errorf("Error marshalling coap message to JSON: %v", err)
				res := &coap.Message{
					Type:      coap.Acknowledgement,
					Code:      coap.Content,
					MessageID: m.MessageID,
					Token:     m.Token,
					Payload:   []byte("数据序列化异常"),
				}
				res.SetOption(coap.ContentFormat, coap.TextPlain)
				return res
			}
			PushToQueue("pre_coap_handler", jsonData)
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("数据处理成功"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			SetLastOpTime(a.String())
			DataHandlerCount()
			return res
		} else {
			res := &coap.Message{
				Type:      coap.Acknowledgement,
				Code:      coap.Content,
				MessageID: m.MessageID,
				Token:     m.Token,
				Payload:   []byte("你没有认证，请认证"),
			}
			res.SetOption(coap.ContentFormat, coap.TextPlain)
			return res
		}
	}
	return nil
}

type CoapMessage struct {
	Uid     string `json:"uid"`
	Message string `json:"message"`
}

func FindDeviceMappingUP(deviceId string) (string, string) {
	zap.S().Infof("FindDeviceMappingUP 开始, deviceId = %v", deviceId)
	i := globalRedisClient.Exists(context.Background(), "auth:coap").Val()
	if i >= 0 {

		// todo: 从redis中根据deviceId获取用户名和密码
		val := globalRedisClient.HGet(context.Background(), "auth:coap", deviceId).Val()
		var auth Auth
		err := json.Unmarshal([]byte(val), &auth)
		if err != nil {
			zap.S().Errorf("Error unmarshalling auth to JSON: %v", err)
			return "", ""
		}
		return auth.Username, auth.Password
	}
	return "", ""
}
